/*Patrick Heisel -- Client Entry April 2011*/
package com.cs252.AudioTest;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;

import android.media.AudioManager;

//This class is responsible for the client end of networking
public class Communicator 
{
	String srvIP;//ServerIP
	int srvPort;//ServerPort
	String name;//Username on server
	Socket tcpSock;//Socket for TCP
	PrintWriter out;//Output Stream writer
	BufferedReader data;//Input Stream reader
	final int UPORT = 4401;//Port for UDP listen
	DatagramSocket dsock = null;//Datagram socket
	int friend;//integer of index in server's client array, 
	//this will be put into the UDP packets, and will serve as a "routing address"
	//for where clients voice should go
	AudioRecordTest owner;//Calling class
	int packSize;//packet size for UDP
	short counter = 1;//udp counter
	String fname;//friends name
    public Communicator(String serverip, int port, String name, AudioRecordTest owner, int packSize) throws Exception
    {
    	//Set instance variables and connect to TCP
    	this.packSize = packSize;
    	this.owner = owner;
    	srvIP = serverip;
    	srvPort = port;
    	this.name = name;
    	InetAddress serverAddr = InetAddress.getByName(srvIP);
		tcpSock = new Socket(serverAddr, port);
		out = new PrintWriter(new BufferedWriter(
						new OutputStreamWriter(tcpSock.getOutputStream())), true);
		out.println(name);
		data = new BufferedReader(new InputStreamReader(tcpSock.getInputStream()));
		listen();
    }
    //MESSAGE LOOP FOR TCP
    public void listen()
    {
    	Runnable fireCommand = new Runnable()
		{
			public void run()
			{
				try
				{
					while(true)
					{
						String str = data.readLine();//get message
						//indicates name list inbound
						if(str.equals("nameup"))
						{
							owner.names.clear();//clear array
							//read in array names until "end"
							while(true)
							{
								str = data.readLine();
								if(str.equals("end"))
									break;
								else
									owner.names.add(str);
							}
							//Causes a list update in Calling object
							synchronized(owner.listLock){
								owner.listLock.notifyAll();								
							}
						}
						//A call should begin
						else if(str.contains("UDPIN"))
						{
							//Parse friend data, start sending packets
							friend = Integer.parseInt(str.substring(6));
							fname = data.readLine();
							udpRoll(str.charAt(0));
							owner.startRecording();
						}
						//Disconnect from call!
						else if(str.contains("end")){
							//Stop recording.
							synchronized (owner.lock){
			                	owner.running = false;
			                	owner.lock.notifyAll();
			                }
			                owner.am.setMode(AudioManager.MODE_NORMAL);
						}
						//You can't connect to that person!
						else if(str.contains("n")){
							owner.handler.sendEmptyMessage(3);
						}
					}
				}
				catch(Exception e)
				{
					System.out.println("sockerr" + e);
				}
			}
		};
		new Thread(fireCommand).start();//Above will all run in thread
    }
    //Continuously Reads UDP packets and plays them
    public void udpRoll(char a)
    {
    	Runnable fireCommand = new Runnable()
		{
			public void run()
			{
				try
				{
					/* Create new UDP-Socket */
					dsock = new DatagramSocket(4402);
					
					while(true)
					{
						byte[] buf = new byte[packSize + 5];
						/* Prepare a UDP-Packet that can
						 * contain the data we want to receive */
						DatagramPacket packet = new DatagramPacket(buf, buf.length);
						//play the packets
						dsock.receive(packet);
						owner.playBuffer(buf, 5, packSize);   
					}
				}
				catch(Exception e)
				{
					System.out.println("sockerr" + e);
				}
			}
		};
		new Thread(fireCommand).start();
		owner.fname = fname;
		//Ask user to accept call (if they are being called)
		if(a == '1')
			owner.handler.sendEmptyMessage(1);
    }
    //Sends some audio
    public void sendBuffer(byte [] buf) throws Exception
    {
		if(dsock != null)
		{
			//Initialize header info
			buf[0] = 55;
			buf[1] = (byte)friend;
			buf[2] = (byte)512;
			buf[3] = (byte)(counter >> 8);
			buf[4] = (byte)(counter);
			//send the packet through
			DatagramSocket ldSock = new DatagramSocket();
			DatagramPacket pack = new DatagramPacket(buf, packSize + 5, InetAddress.getByName(srvIP), 4401);
			ldSock.send(pack);
		}
		counter ++;
    }
    //Calls "name"
    public void specific(String name)
    {
    	out.println("c2: " + name);
    }
    //Tells server that we accept a call
    public void allow(){
    	out.println("yes");
    }
    //Ends a call
    public void end(){
    	out.println("end");
    }
}





